bitkeeper revision 1.119 (3e6c96c2opjGKDx0oCP831RfhP4uDw)
authorkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>
Mon, 10 Mar 2003 13:44:34 +0000 (13:44 +0000)
committerkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>
Mon, 10 Mar 2003 13:44:34 +0000 (13:44 +0000)
hypervisor.c, network.c:
  Added locing to page-table update code in Xenolinux. Network driver noew flushed the update queue before pushing new rx buffers.

xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/network/network.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c

index 7ef9ce4ef88e289432f2e690eb428443b2c1c93e..7e85bf5abe0dd8996790d7cf6a5b3980c685db42 100644 (file)
@@ -240,6 +240,11 @@ static void network_alloc_rx_buffers(struct net_device *dev)
 
     np->net_ring->rx_event = RX_RING_INC(np->rx_idx);
 
+    /*
+     * We may have allocated buffers which have entries outstanding in
+     * the page update queue -- make sure we flush those first!
+     */
+    flush_page_update_queue();
     HYPERVISOR_net_update();
 }
 
index b051684aa2b756ce82cdd923086f628b089adbdf..044c531d35a2ccaab3189ccf71e7e54ca13508ab 100644 (file)
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+/*
+ * This suffices to protect us if we ever move to SMP domains.
+ * Further, it protects us against interrupts. At the very least, this is
+ * required for the network driver which flushes the update queue before
+ * pushing new receive buffers.
+ */
+static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
+
 #define QUEUE_SIZE 2048
 static page_update_request_t update_queue[QUEUE_SIZE];
 unsigned int pt_update_queue_idx = 0;
@@ -79,7 +87,9 @@ unsigned long pt_baseptr;
 
 void _flush_page_update_queue(void)
 {
-    if ( idx == 0 ) return;
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
+    if ( idx == 0 ) goto out;
 #if PT_UPDATE_DEBUG > 1
     printk("Flushing %d entries from pt update queue\n", idx);
 #endif
@@ -88,6 +98,8 @@ void _flush_page_update_queue(void)
 #endif
     HYPERVISOR_pt_update(update_queue, idx);
     idx = 0;
+ out:
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 static void increment_index(void)
@@ -97,72 +109,99 @@ static void increment_index(void)
 
 void queue_l1_entry_update(unsigned long ptr, unsigned long val)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
 #if PT_UPDATE_DEBUG > 0
     DEBUG_disallow_pt_read(ptr);
 #endif
     update_queue[idx].ptr = phys_to_machine(ptr);
     update_queue[idx].val = val;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_l2_entry_update(unsigned long ptr, unsigned long val)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr = phys_to_machine(ptr);
     update_queue[idx].val = val;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_pt_switch(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = phys_to_machine(ptr);
     update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_NEW_BASEPTR;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_tlb_flush(void)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_TLB_FLUSH;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_invlpg(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = ptr & PAGE_MASK;
     update_queue[idx].val |= PGEXT_INVLPG;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_pgd_pin(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = phys_to_machine(ptr);
     update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_PIN_L2_TABLE;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_pgd_unpin(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = phys_to_machine(ptr);
     update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_UNPIN_TABLE;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_pte_pin(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = phys_to_machine(ptr);
     update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_PIN_L1_TABLE;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }
 
 void queue_pte_unpin(unsigned long ptr)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
     update_queue[idx].ptr  = phys_to_machine(ptr);
     update_queue[idx].ptr |= PGREQ_EXTENDED_COMMAND;
     update_queue[idx].val  = PGEXT_UNPIN_TABLE;
     increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
 }